package src;

/**
 * The Power class, in which implements the Expression Interface
 * represents the Power Expression (i.e., a^b, where a is expression and b is double)
 * A power expression can be evaluated, derived and return its last operation symbol.
 *
 * @author Intro111 Staff
 */

public class Power implements Expression {

    private Expression base;
    private double exponent;


    /**
     * Constructor in which creates the power expression
     *
     * @param base     the base expression
     * @param exponent the exponent value
     * @throws RuntimeException for null input expression
     */
    public Power(Expression base, double exponent) {
        if (base == null) {
            throw new RuntimeException("Power constructor got a null argument.");
        }
        this.base = base;
        this.exponent = exponent;
    }

    /**
     * Returns the last operation symbol of the power Expression
     *
     * @return String "^" that represents the last operation
     */

    public String getLastOperationSymbol() {
        return "^";
    }

    /**
     * Evaluates the power expression
     *
     * @return double that represents the evaluation of the power expression
     */
    public double evaluate() {
        double value =   Math.pow(base.evaluate(), exponent);
        if (Double.isNaN(value)) throw new RuntimeException("Bad arguments for Power "+base+"="+base.evaluate()+" and "+exponent);
        return value;
    }

    /**
     * Derives the power expression by a variable.
     *
     * @param var the variable to derive by
     * @return the derived expression by param var
     * @throws RuntimeException for a null var
     */
    public Expression derivative(Variable var) {
        if (var == null) {
            throw new RuntimeException("Power derivative(Variable var) got a null argument.");
        }

        Expression a = new Constant(exponent);
        Expression b = new Power(base, exponent - 1);
        Expression c = new Multiplication(a, b);
        Expression derivative = new Multiplication(c, base.derivative(var));
        return derivative;
    }

    /**
     * Compares this power expression to the specified object.
     * The result is true if and only if the argument is not null, the argument is instance of Power expression and the base expressions are equals and the exponents values are equals as well.
     *
     * @param other The object to compare this expression against
     * @return true if the given object represents an expression equivalent to this expression, false otherwise
     */
    public boolean equals(Object other) {
        return ((other instanceof Power) &&
                (base.equals(((Power) other).base)) &&
                (exponent == ((Power) other).exponent));
    }

    /**
     * Returns a string representing the power expression.
     *
     * @return String that represents the power expression
     */
    public String toString() {
        return "(" + base.toString() + getLastOperationSymbol() + exponent + ")";
    }
}
